package com.atguigu.crowd.handler;

import com.atguigu.crowd.api.MySQLRemoteService;
import com.atguigu.crowd.api.RedisRemoteService;
import com.atguigu.crowd.constant.CrowdConstant;
import com.atguigu.crowd.entity.po.MemberPO;
import com.atguigu.crowd.entity.vo.MemberLoginVO;
import com.atguigu.crowd.entity.vo.MemberVO;
import com.atguigu.crowd.util.ResultEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author cyb315
 * @create 2021-11-07 17:55
 */
@Controller
public class MemberHandler {

    private Logger logger = LoggerFactory.getLogger(MemberHandler.class);

    @Autowired
    private RedisRemoteService redisRemoteService;

    @Autowired
    private MySQLRemoteService mySQLRemoteService;

    /**
     * 发送短信验证码并执行保存的ajax请求映射方法
     *
     * @param phoneNum 用户填写的手机号码
     * @return
     */
    @ResponseBody
    @RequestMapping("/auth/member/send/short/message.json")
    public ResultEntity<String> sendMessage(@RequestParam("phoneNum") String phoneNum) {
        // 1.发送验证码到手机

        // 2.判断发送结果

        // 3.如果成功，将验证码存入redis

        // 3.1声明验证码数据键，值，超时时间及单位
        // 3.1.1键
        String key = CrowdConstant.REDIS_CODE_PREFIX + phoneNum;
        // 3.1.2值
        String data = "111111";
        // 3.1.3超时时间数
        long time = 15;
        // 3.1.4超时时间单位
        TimeUnit timeUnit = TimeUnit.MINUTES;

        // 3.2执行保存
        // 3.2.1调用redis远程方法
        ResultEntity<String> savaCodeEntity = redisRemoteService.setRedisKeyValueRemoteWithTimeout(key, data, time, timeUnit);
        // 3.2.2判断是否保存成功
        if (ResultEntity.SUCCESS.equals(savaCodeEntity.getResult())) {
            return ResultEntity.successWithoutData();
        } else {
            return ResultEntity.failed("存入失败！请重试");
        }

    }

    /**
     * 会员注册请求映射方法
     *
     * @param memberVO 接收表单数据的JavaBean
     * @return
     */
    @RequestMapping("/auth/do/member/register")
    public String register(MemberVO memberVO, ModelMap modelMap) {

        // 1.获取用户输入的手机号
        String phoneNum = memberVO.getPhoneNum();

        // 2.拼接redis的验证码key
        String key = CrowdConstant.REDIS_CODE_PREFIX + phoneNum;

        // 3.从redis中读取key对应的value
        ResultEntity<String> resultEntity = redisRemoteService.getRedisStringValueByKeyRemote(key);

        // 4.检查查询操作是否有效
        String result = resultEntity.getResult();
        // 从redis中获取操作失败
        if (ResultEntity.FAILED.equals(result)) {
            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, resultEntity.getMessage());
            return "member-reg";
        }
        // 获取操作成功但验证码为空
        String redisCode = resultEntity.getData();
        if (redisCode == null) {
            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_CODE_NOT_EXISTS);
            return "member-reg";
        }

        // 5.如果从redis中能够查询到非空的value则比较表单验证码和redis里取到的验证码
        String formCode = memberVO.getCode();
        // 如果不一致给出异常信息
        if (!Objects.equals(redisCode, formCode)) {
            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_CODE_INVALID);
            return "member-reg";
        }

        // 6.如果验证码一致，则验证码从redis里删除（验证码用过就要删除）
        redisRemoteService.removeRedisKeyRemote(key);

        // 7.执行密码加密
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String userpswdBeforeEncode = memberVO.getUserpswd();
        String userpswdAfterEncode = passwordEncoder.encode(userpswdBeforeEncode);
        // 把加密后的密码重新保存回memberVO对象
        memberVO.setUserpswd(userpswdAfterEncode);

        // 8.执行memberPO对象的保存
        MemberPO memberPO = new MemberPO();
        // 复制相同的属性，spring提供的方法
        BeanUtils.copyProperties(memberVO, memberPO);
        // 执行保存操作
        ResultEntity<String> saveResultEntity = mySQLRemoteService.saveMember(memberPO);
        // 如果保存失败，处理异常
        if (ResultEntity.FAILED.equals(saveResultEntity.getResult())) {
            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, saveResultEntity.getMessage());
            return "member-reg";
        }

        // 9.保存成功后重定向到会员登录页面
        return "redirect:http://localhost/auth/member/to/login/page.html";

    }

    /**
     * 会员登录的请求控制方法
     *
     * @param loginacct
     * @param userpswd
     * @return
     */
    @RequestMapping("/auth/member/do/login")
    public String login(@RequestParam("loginacct") String loginacct, @RequestParam("userpswd") String userpswd, ModelMap modelMap, HttpSession session) {

        // 1.根据账号查询MemberPO对象
        ResultEntity<MemberPO> memberPOResultEntity = mySQLRemoteService.getMemberPOByLoginAcctRemote(loginacct);
        // 1.1查询失败处理
        if (ResultEntity.FAILED.equals(memberPOResultEntity.getResult())) {
            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, memberPOResultEntity.getMessage());
            return "member-login";
        }
        // 返回数据为空处理
//        MemberPO memberPO = memberPOResultEntity.getData();
//        if (memberPO == null) {
//            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_LOGIN_FAILED);
//            return "member-login";
//        }

        // 2.比较密码是否正确
        // 2.1从ResultEntity对象中获取查询到的MemberPO对象
        MemberPO memberPO = memberPOResultEntity.getData();
        // 2.2获取查询到的密码
        String userpswdDataBase = memberPO.getUserpswd();
        // 2.3调用matches()方法，将表单密码加密后与数据库加密密码进行比较
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        boolean matchesResult = passwordEncoder.matches(userpswd, userpswdDataBase);
        // 2.4密码不正确的处理
        if (!matchesResult) {
            // 如果密码不正确
            modelMap.addAttribute(CrowdConstant.ATTR_NAME_MESSAGE, CrowdConstant.MESSAGE_LOGIN_FAILED);
            return "member-login";
        }

        // 3.密码正确，创建一个MemberLoginVO对象，存入session域
        MemberLoginVO memberLoginVO = new MemberLoginVO(memberPO.getId(), memberPO.getUsername(), memberPO.getEmail());
        session.setAttribute(CrowdConstant.ATTR_NAME_LOGIN_MEMBER, memberLoginVO);
        // 测试：控制台日志打印
        logger.debug(memberLoginVO.getUsername());

        // 4.重定向回会员主页面
        return "redirect:http://localhost/auth/member/to/center/page";
    }

    /**
     * 会员退出登录的请求映射方法
     *
     * @param session
     * @return
     */
    @RequestMapping("/auth/member/logout")
    public String logout(HttpSession session) {
        // 1.让会员登录信息session过期
        session.invalidate();
        // 2.重定向回首页
        return "redirect:http://localhost";
    }


}
